package com.ap.core.jaxb.impl;

import com.ap.core.jaxb.UnmarshallerException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.util.concurrent.ConcurrentHashMap;

public class JaxbMarshallerFactory {

    /**
     * Store JAXB context cache against context
     */
    private static final ConcurrentHashMap<String, JAXBContext> CONTEXT_PATH_CACHE = new ConcurrentHashMap<String, JAXBContext>();

    /**
     * 
     * Default constructor
     * 
     */
    private JaxbMarshallerFactory() {

    }

    /**
     * Get Unmarshaller for a given context path
     * 
     * @return
     * @throws javax.xml.bind.JAXBException
     */
    public static final Unmarshaller getUnmarshaller(final String contextPath) throws UnmarshallerException {

        final Unmarshaller unmarshaller;
        try {
            unmarshaller = getJaxbContext(contextPath).createUnmarshaller();
        } catch (JAXBException exception) {
            throw new UnmarshallerException("Problem obtaining JAXB Context: " + exception.getMessage(), exception);
        }

        return unmarshaller;
    }

    /**
     * Get JAXBContext for a given context path
     * 
     * @return
     * @throws javax.xml.bind.JAXBException
     */
    public static final JAXBContext getJaxbContext(final String contextPath) throws JAXBException {

        final JAXBContext jaxbContext;
        if (CONTEXT_PATH_CACHE.containsKey(contextPath)) {
            jaxbContext = CONTEXT_PATH_CACHE.get(contextPath);
        } else {
            final JAXBContext newJaxbContext =   JAXBContext.newInstance(contextPath);
            final JAXBContext previousJaxbContext = CONTEXT_PATH_CACHE.putIfAbsent(contextPath, newJaxbContext);
            jaxbContext = previousJaxbContext == null ? newJaxbContext : previousJaxbContext;
        }

        return jaxbContext;
    }


}
